﻿using System;
using System.ComponentModel.Composition;
using System.Web.Mvc;
using System.Globalization;
using AxeFrog.Composition;
using AxeFrog.Data;

namespace AxeFrog.Web
{
	[PartCreationPolicy(CreationPolicy.NonShared)]
	public class BaseController : Controller
	{
		public BaseController()
		{
			RequestContext.Controller = this;
		}

		private ConnectionContextProvider _ccp;
		public ConnectionContextProvider ConnectionContextProvider
		{
			get { return _ccp ?? (_ccp = Container.Resolve<ConnectionContextProvider>()); }
		}
		public ConnectionContext Connect()
		{
			return (_ccp ?? (_ccp = Container.Resolve<ConnectionContextProvider>())).Connect();
		}

		#region Container Access
		protected T Create<T>()
		{
			return ((WebApplication)HttpContext.ApplicationInstance).Container.Resolve<T>();
		}
		#endregion

		#region Redirect and SetResult
		protected void SetResult(bool success, string message)
		{
			TempData["ActionResult.HasError"] = success;
			TempData["ActionResult.Message"] = message;
		}

		protected void SetResult(string infomessage)
		{
			TempData["ActionResult.Message"] = infomessage;
		}

		protected RedirectResult Redirect(bool success, string message, string url)
		{
			SetResult(success, message);
			return Redirect(url);
		}

		protected RedirectToRouteResult RedirectToAction(bool success, string message, string actionName)
		{
			SetResult(success, message);
			return RedirectToAction(actionName);
		}

		protected RedirectToRouteResult RedirectToAction(bool success, string message, string actionName, object values)
		{
			SetResult(success, message);
			return RedirectToAction(actionName, values);
		}

		protected RedirectToRouteResult RedirectToAction(bool success, string message, string actionName, string controller)
		{
			SetResult(success, message);
			return RedirectToAction(actionName, controller);
		}

		protected RedirectToRouteResult RedirectToAction(bool success, string message, string actionName, string controller, object values)
		{
			SetResult(success, message);
			return RedirectToAction(actionName, controller, values);
		}

		protected RedirectToRouteResult RedirectToRoute(bool success, string message, string routeName)
		{
			SetResult(success, message);
			return RedirectToRoute(routeName);
		}

		protected RedirectToRouteResult RedirectToRoute(bool success, string message, object values)
		{
			SetResult(success, message);
			return RedirectToRoute(values);
		}

		protected RedirectToRouteResult RedirectToRoute(bool success, string message, string routeName, object values)
		{
			SetResult(success, message);
			return RedirectToRoute(routeName, values);
		}

		protected ActionResult RedirectToLogin(bool redirectAfterLogin)
		{
			SetResult(false, "Please log in to access that area");
			object o = redirectAfterLogin ? new { r = Request.Url.ToString() } : new object();
			return RedirectToAction("Login", "Account", o);
		}

		protected ActionResult RedirectToLogin()
		{
			return RedirectToLogin(true);
		}
		#endregion

		#region Public Redirect (for action filters)
		public static ActionResult RerouteToLogin(string message)
		{
			AssertInheritsFromBaseController();
			return RequestContext.Controller.RedirectToRoute(false, message, "login", new { r = System.Web.HttpContext.Current.Request.Url.ToString() });
		}
		public static ActionResult RerouteToIndex(string message)
		{
			AssertInheritsFromBaseController();
			return RequestContext.Controller.RedirectToRoute(false, message, "index");
		}
		public static ActionResult RerouteToLogin()
		{
			AssertInheritsFromBaseController();
			return RequestContext.Controller.RedirectToRoute("login", new { r = System.Web.HttpContext.Current.Request.Url.ToString() });
		}
		public static ActionResult RerouteToCreatePassword()
		{
			AssertInheritsFromBaseController();
			return RequestContext.Controller.RedirectToRoute("createpassword", new { r = System.Web.HttpContext.Current.Request.Url.ToString() });
		}

		private static void AssertInheritsFromBaseController()
		{
			if(RequestContext.Controller == null)
				throw new Exception("The controller needs to inherit from BaseController");
		}
		#endregion

		protected UserContext CurrentUser
		{
			get { return RequestContext.CurrentUser; }
		}

		protected override void ExecuteCore()
		{
			// Prevent ASP.Net from intercepting post requests containing script tags and other content
			// that it deems to be "malicious" - we'll handle that ourselves
			ValidateRequest = false;
			base.ExecuteCore();
		}

		public ContainerManager Container
		{
			get { return RequestContext.Container; }
		}

		protected override void OnActionExecuting(ActionExecutingContext filterContext)
		{
			ViewData["Action"] = ValueProvider.GetValue("action").RawValue;
			ViewData["Controller"] = ValueProvider.GetValue("controller").RawValue;
			base.OnActionExecuting(filterContext);
		}

		protected ActionResult AjaxNothing()
		{
			return Json(new object());
		}

		public T Form<T>(string name)
		{
			Type t = typeof(T);
			string val = Request.Form[name];
			object o;
			if(t == typeof(string))
			{
				o = val;
			}
			else if (t == typeof(bool))
			{
				o = val == "true,false" || val == "True" || val == "true";
			}
			else if (t == typeof(int?))
			{
				int n; o = int.TryParse(val, out n) ? (int?)n : null;
			}
			else if (t == typeof(int))
			{
				o = val.ToInt();
			}
			else if (t.IsEnum || (t.IsNullableValueType() && Nullable.GetUnderlyingType(t).IsEnum))
			{
				o = val.ToEnum<T>();
			}
			else if (t == typeof(long?))
			{
				long n; o = long.TryParse(val, out n) ? (long?)n : null;
			}
			else if (t == typeof(long))
			{
				o = val.ToLong();
			}
			else if (t == typeof(double?))
			{
				double n; o = double.TryParse(val, out n) ? (double?)n : null;
			}
			else if (t == typeof(double))
			{
				o = val.ToDecimal();
			}
			else
				throw new NotImplementedException("Method does not support " + t);
			SetModelValue(name, o);
			return (T)o;
		}

		public void SetModelValue(string name, object value)
		{
			//ValueProvider[name] = new ValueProviderResult(value, Request.Form[name], CultureInfo.InvariantCulture);
			//ModelState.SetModelValue(name, ValueProvider[name]);
			ModelState.SetModelValue(name, new ValueProviderResult(value, Request.Form[name], CultureInfo.InvariantCulture));
		}
	}
}